package net.xdclass.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import net.xdclass.config.MqConfig;
import net.xdclass.enums.BizCodeEnum;
import net.xdclass.enums.StockTaskStateEnum;
import net.xdclass.exception.BizException;
import net.xdclass.mapper.ProductMapper;
import net.xdclass.mapper.ProductTaskMapper;
import net.xdclass.model.ProductDO;
import net.xdclass.model.ProductRecordMessage;
import net.xdclass.model.ProductTaskDO;
import net.xdclass.request.LockProductRequest;
import net.xdclass.request.OrderItemRequest;
import net.xdclass.service.ProductService;
import net.xdclass.vo.ProductVo;
import org.checkerframework.checker.units.qual.A;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 孙浩
 * @since 2022-04-24
 */
@Slf4j
@Service
public class ProductServiceImpl implements ProductService {

  @Autowired
  private ProductMapper productMapper;

  @Autowired
  private ProductTaskMapper productTaskMapper;

  @Autowired
  private RabbitTemplate rabbitTemplate;

  @Autowired
  private MqConfig mqConfig;

  @Override
  public AtomicReference<HashMap<String, Object>> page(Integer page, Integer size) {
    Page<ProductDO> pageInfo = new Page<>();
    Page<ProductDO> productDOPage = productMapper.selectPage(pageInfo,
        new QueryWrapper<ProductDO>().orderByDesc("create_time"));

    AtomicReference<HashMap<String, Object>> dataMap = new AtomicReference<>(new HashMap<>(size));
    dataMap.get().put("total_record", productDOPage.getTotal());

    dataMap.get().put("total_page", productDOPage.getPages());

    dataMap.get().put("current_data", productDOPage.getRecords().stream().map(this::transformation).collect(Collectors.toList()));

    return dataMap;
  }


  private ProductVo transformation(ProductDO productDO) {
    ProductVo productVo = new ProductVo();
    BeanUtils.copyProperties(productDO, productVo);
    productVo.setStock(productDO.getStock() - productDO.getLockStock());
    return productVo;
  }

  @Override
  public ProductVo detail(String productId) {
    ProductDO productDO = productMapper.selectOne(new QueryWrapper<ProductDO>().eq("id", productId));
    if (null == productDO) {
      throw new BizException(BizCodeEnum.PRODUCT_NOT_EXIT);
    }
    return transformation(productDO);
  }

  @Override
  public void lockProducts(LockProductRequest lockProductRequest) {
    String orderOutTradeNo = lockProductRequest.getOrderOutTradeNo();
    List<OrderItemRequest> orderItemRequests = lockProductRequest.getOrderItemRequests();
    List<Long> productIdList = orderItemRequests.stream().map(OrderItemRequest::getProductId).collect(Collectors.toList());
    List<ProductDO> productDOList = productMapper.selectList(new QueryWrapper<ProductDO>().in("id", productIdList));
    Map<Long, ProductDO> productDOMap = productDOList.stream().collect(Collectors.toMap(ProductDO::getId, Function.identity()));
    for (OrderItemRequest orderItemRequest : orderItemRequests) {
      ProductDO productDO = productDOMap.get(orderItemRequest.getProductId());
      int rows = productMapper.lockProductStock(productDO.getId(), orderItemRequest.getBuyNum());
      if (rows != 1) {
        throw new BizException(BizCodeEnum.ORDER_CONFIRM_LOCK_PRODUCT_FAIL);
      }
      ProductTaskDO productTaskDO = new ProductTaskDO();
      productTaskDO.setProductId(productDO.getId());
      productTaskDO.setBuyNum(orderItemRequest.getBuyNum());
      productTaskDO.setProductName(productDO.getTitle());
      productTaskDO.setOutTradeNo(orderOutTradeNo);
      productTaskDO.setCreateTime(new Date());
      productTaskDO.setLockState(StockTaskStateEnum.LOCK.name());
      productTaskMapper.insert(productTaskDO);
      //发送MQ延时消息
      ProductRecordMessage productRecordMessage = new ProductRecordMessage();
      productRecordMessage.setTaskId(productTaskDO.getId());
      productRecordMessage.setOutTradeNo(orderOutTradeNo);
      log.info("发送延时队列{}",productRecordMessage);
      rabbitTemplate.convertAndSend(mqConfig.getEventExchange(), mqConfig.getProductReleaseDelayRoutingKey(), productRecordMessage);
    }
  }
}
